package board.grid;
/** The directions to all of the spaces within
 *  one space from a center point.  Degree measures
 *  start at the right and go counter-clockwise.  
 *  
 *  All degree values are stored as multiples of 45. 
 *  <code> 0 <= value <= 315 && value % 45 == 0 </code>
 */
public enum Direction {
								//DLUR
	RIGHT(0, (byte) 1),			//0001 = 1
	UP_RIGHT(45, (byte) 3),		//0011 = 3
	UP(90, (byte) 2),			//0010 = 2
	UP_LEFT(135, (byte) 6),		//0110 = 6
	LEFT(180, (byte) 4),		//0100 = 4
	DOWN_LEFT(225, (byte) 12),	//1100 = 12
	DOWN(270, (byte) 8),		//1000 = 8
	DOWN_RIGHT(315, (byte) 9),	//1001 = 9
	NONE(-1, (byte) 0);			//0000 = 0
	/** The integer value of the direction, 
	 *  in degrees.  This will always be a
	 *  multiple of 45 and between 0 and 315, 
	 *  inclusive.  
	 */
	private int		degreeValue;
	/** A helper variable used to determine the
	 *  horizontal and vertical components of
	 *  each direction.  This is used in the
	 *  <code>isUp()</code>, <code>isDown()</code>, 
	 *  <code>isLeft()</code>, and <code>isRight()</code>
	 *  methods.  
	 */
	private byte	composite;
	/** A constructor to set the private fields
	 * 
	 * @param degreeValue - the integer representation of the direction, in degrees
	 * @param composite - the helper value
	 */
	private Direction(int degreeValue, byte composite){
		this.degreeValue = degreeValue; 
		this.composite = composite;
	}
	/** Get the composite form of the direction.  
	 *  This represents the four (currently)
	 *  boolean values of the angle.  
	 * 
	 * @return - the composite form
	 */
	protected byte getComposite() {return composite;}
	/** Get the degree value of the direction, 
	 *  starting at the right, and going counter-
	 *  clockwise.  This will always be a multiple
	 *  of 45 and <code> 0 <= value <= 315 </code>.  
	 * 
	 * @return - the degree equivalent 
	 */
	public int getDegreeValue() {return degreeValue;}
	/** Does the direction have a positive x component.  
	 * 
	 * @return - does the direction point right
	 */
	public boolean isRight()	{return (getComposite() & RIGHT.getComposite()) == RIGHT.getComposite();}
	/** Does the direction have a negative x component.  
	 * 
	 * @return - does the direction point left
	 */
	public boolean isLeft()		{return (getComposite() & LEFT.getComposite()) == LEFT.getComposite();}
	/** Does the direction have a positive y component.  
	 * 
	 * @return - does the direction point up
	 */
	public boolean isUp()		{return (getComposite() & UP.getComposite()) == UP.getComposite();}
	/** Does the direction have negative y component.  
	 * 
	 * @return - does the direction point down 
	 */
	public boolean isDown()		{return (getComposite() & DOWN.getComposite()) == DOWN.getComposite();}
	/** Get the value of the change in y.  
	 *  This will always return -1, 0, 1.  
	 *  
	 * 
	 * @return - -1 = down, 0 = none, 1 = up.  
	 */
	public int getDeltaY() {
		if(isUp())
			return 1;
		else if(isDown())
			return -1;
		else
			return 0;
	}
	/** Get the value of the change in x.  
	 *  This will always return -1, 0, 1.  
	 *  
	 * @return - -1 = left, 0 = none, 1 = right.  
	 */
	public int getDeltaX() {
		if(isLeft())
			return -1;
		else if(isRight())
			return 1;
		else
			return 0;
	}
	/** Get the direction for a given degree
	 *  value. This will always round to the
	 *  nearest multiple of 45.  It will also
	 *  normalize it to be between 0 and 360.  
	 *  NONE should never be returned.  
	 * 
	 * @param degrees - the degree value for which to get the nearest direction
	 * @return - the requested direction 
	 */
	public static Direction fromDegrees(int degrees) {
		degrees %= 360;
		if(degrees < 0)
			degrees += 360;
		degrees = (degrees / 45) * 45;
		for(Direction dir : values())
			if(dir.getDegreeValue() == degrees)
				return dir;
		//This shouldn't happen, but Java said I have to add it.  :P
		return NONE;
	}
}
